#include "udpserver.hpp"
#include <memory>
#include <fstream>
#include <unordered_map>
#include <unistd.h>
#include <signal.h>
using namespace Server;
const std::string dictTxt = "./dict.txt";
std::unordered_map<std::string, std::string> dict;
static void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " local_port\n\n";
}
static bool cutString(const std::string target, std::string *key, std::string *value, const std::string &sep)
{
    auto pos = target.find(sep, 0);
    if (pos == std::string::npos)
    {
        return false;
    }
    *key = target.substr(0, pos);
    *value = target.substr(pos + sep.size());
    return true;
}
static void initDict()
{
    std::ifstream in(dictTxt, std::ios::binary);
    if (!in.is_open())
    {
        std::cerr << "open file :" << dictTxt << " error" << std::endl;
        exit(OPEN_ERR);
    }
    std::string line;
    std::string key, value;
    while (getline(in, line))
    {
        if (cutString(line, &key, &value, ":"))
        {
            dict.insert(make_pair(key, value));
        }
    }
    in.close();
    std::cout << "load dict success" << std::endl;
}
static void debugPrint()
{
    for (auto &dt : dict)
    {
        std::cout << dt.first << " # " << dt.second << std::endl;
    }
}
void load(int signo)
{
    (void)signo;
    initDict();
}
void handlerMessage(int sockfd, std::string clientip, uint16_t clientport, std::string message)
{
    std::string response_message;
    auto pos = dict.find(message);
    if (pos == dict.end())
    {
        response_message = "unknown";
    }
    else
    {
        response_message = pos->second;
    }
    struct sockaddr_in client;
    bzero(&client, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_addr.s_addr = inet_addr(clientip.c_str());
    client.sin_port = htons(clientport);
    sendto(sockfd, response_message.c_str(), response_message.size(), 0, (struct sockaddr *)&client, sizeof(client));
}
void execCommand(int sockfd, std::string clientip, uint16_t clientport, std::string cmd)
{
    if (cmd.find("rm") != std::string::npos || cmd.find("mv") != std::string::npos || cmd.find("mkdir") != std::string::npos)
    {
        std::cout << clientip << " : " << clientport << " 正在做一个非法的操作 : " << cmd << std::endl;
        return;
    }
    std::string response;
    FILE *fp = popen(cmd.c_str(), "r");
    if (fp == nullptr)
    {
        response = cmd + " exec failed";
    }
    char line[1024];
    while (fgets(line, sizeof(line), fp))
    {
        response += line;
    }
    pclose(fp);
    struct sockaddr_in client;
    bzero(&client, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_addr.s_addr = inet_addr(clientip.c_str());
    client.sin_port = htons(clientport);
    sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&client, sizeof(client));
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    signal(2, load);
    initDict();
    debugPrint();
    // std::unique_ptr<UdpServer> usvr(new UdpServer(execCommand, port));
    std::unique_ptr<UdpServer> usvr(new UdpServer(handlerMessage, port));
    usvr->initServer();
    usvr->start();
    return 0;
}